package com.lmxdawn.api.admin.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.lmxdawn.api.admin.dao.auth.AuthAdminDao;
import com.lmxdawn.api.admin.dao.auth.AuthRoleAdminDao;
import com.lmxdawn.api.admin.dao.auth.AuthRoleDao;
import com.lmxdawn.api.admin.entity.auth.AuthAdmin;
import com.lmxdawn.api.admin.entity.auth.AuthRole;
import com.lmxdawn.api.admin.entity.auth.AuthRoleAdmin;
import io.jsonwebtoken.*;
import io.lettuce.core.RedisClient;
import lombok.val;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * jwt
 */
public class JwtUtils {



    public static void setCurrentUser(String id, HttpServletRequest request){
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        if(redisUtil.get(String.format("USER_LOCAL:%s", id)) != null){

            return;
        }
        val adminDao = SpringUtil.getBean(AuthAdminDao.class);
        val adminDto = adminDao.findById(id);

        redisUtil.set(String.format("USER_LOCAL:%s", id), adminDto);
        val roleAdminDao = SpringUtil.getBean(AuthRoleAdminDao.class);
        List<AuthRoleAdmin> authRoleAdmins = roleAdminDao.listByAdminId(id);
        val roleList = authRoleAdmins.stream().map(AuthRoleAdmin::getRoleId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(roleList)){
            val roleDao = SpringUtil.getBean(AuthRoleDao.class);
            List<AuthRole> authRoles = roleDao.listByIdIn(roleList);
            redisUtil.set(String.format("ROLE_LOCAL:%s", id), authRoles);
        }
    }
    public static List<AuthRole> getCurrentUserRoles(String id){
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        return (List<AuthRole>) redisUtil.get(String.format("ROLE_LOCAL:%s", id));
    }
    public static AuthAdmin getCurrentUser(String id){
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        return (AuthAdmin) redisUtil.get(String.format("USER_LOCAL:%s", id));
    }
    /**
     * 生成 token
     *
     * @param claims    自定义的 map
     * @param ttl 过期时间
     * @return
     */
    public static String createToken(Map<String,Object> claims, Long ttl) {
        Key key = generateKey();
        SignatureAlgorithm signatureAlgorithm =  SignatureAlgorithm.HS256;
        Long nowMillis = System.currentTimeMillis(); //生成JWT的时间
        JwtBuilder builder = Jwts.builder()
                .setHeaderParam("typ", "JWT") //设置header
                .setHeaderParam("alg", "HS256")
                .setClaims(claims) //设置payload的键值对
                // .setIssuedAt(now) //设置iat
                // .setIssuer("vue-api")
                .signWith(signatureAlgorithm, key); //签名，需要算法和key
        if (ttl != null && ttl >= 0) {
            Long expMillis = nowMillis + ttl * 1000;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp); //设置过期时间
        }
        return builder.compact();
    }

    /**
     * 生成 token ，没有过期时间
     *
     * @param claims 自定义的 map
     * @return
     */
    public static String createToken(Map<String,Object> claims) {
        return createToken(claims, null);
    }

    /**
     * 解密 jwt
     * @param jwt 创建的 jwt 字符串
     * @return
     */
    public static Claims parse(String jwt) {

        if (jwt == null) {
            return null;
        }

        try {
            return Jwts.parser()
                    .setSigningKey(generateKey())     //此处的key要与之前创建的key一致
                    .parseClaimsJws(jwt)
                    .getBody();
        }catch (ExpiredJwtException e){
            return null;
        }
    }

    /**
     * 获取 key
     *
     * @return
     */
    private static SecretKey generateKey() {
        String stringKey = "veu-api";
        byte[] encodedKey = Base64.decodeBase64(stringKey);
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }
}
